package ewu.anweisungen

import ewu.expressions.ExpArray
import gui.Layout
import java.util.ArrayList
import scala.collection.mutable.ArrayBuffer
import ewu._

/**
 * Diese Klasse erbt von der Anweisung dar und ist fuer die Darstellung eines
 * Funktionsaufrufes der Form "funktion(a, b)" zustaendig.
 */

class AProzedurAufruf(ausdruck: functionExpression, tt: Layout) extends Anweisung {
  
  def this(ausdruck: functionExpression) = this(ausdruck, null)
  
  override def numerate(num: List[Int]) = {
    number = num
    ausdruck.funcconf.numerate(1 :: num)
  }
  
  override def tabbate(i: Int) = {
    tabs = i
    ausdruck.funcconf.tabbate(i+1)
  }

  override def toString(): String = {
    (HM.numberString(number) ++ ausdruck.toString ++ ";\n")
  }
  
  override def toTabString: String = {
    return (HM.tabString(tabs) ++ ausdruck.toString ++ ";\n")
  }

  override def trace(env: Environment, aenv: ArrayEnvironment, tt: Layout, h: Int):
  (String, Boolean, Int) =  {

    var outexp:ArrayList[Expression] = new ArrayList()

    ausdruck.funcconf = new Konfiguration(new Environment().
                                addValues(ausdruck.initconf.umgebung), ausdruck.initconf.teil)
    for(i <- 0 to ausdruck.params.length-1) {
      var tmppara = ausdruck.params(i).evaluate(env) match {
        case Some(x:BigInt) => 
          if(x == BigInt(298171879)) {
            if(ausdruck.params(i).isInstanceOf[Name]) {
              var tet:Expression = env.getArray(ausdruck.params(i).asInstanceOf[Name]) match {
                case x:ExpArray => x
                case _ => null
              }
              if(tet == null)
                Number(BigInt(0))
              else
                tet
            }
            else
              Number(BigInt(0))
          }
          else
            Number(x) 
        case None => Number(BigInt(0))
      }
      var varname = ausdruck.allvars.get(i) match {
        case Some(x) => x
        case None => null
      }

      if(varname != null && ausdruck.inputvars.isDefined(varname)) {
        ausdruck.funcconf.umgebung.setValue(varname, tmppara)
        
        // TODO alle *_anf variablen in den Zusicherungen ersetzen(trace)?
        if(tmppara.isInstanceOf[ExpArray]) {
          var expa = new ExpArray(tmppara.asInstanceOf[ExpArray].range)
          for(k <- 0 to tmppara.asInstanceOf[ExpArray].getArray.length-1) {
            expa.getArray()(k) = tmppara.asInstanceOf[ExpArray].getArray()(k)
          }
          tmppara = expa
        }
        if(ausdruck.funcconf.umgebung.getValue(varname + "_anf") == Some)
          ausdruck.funcconf.umgebung.setValue(varname + "_anf", tmppara)
        else
          ausdruck.funcconf.umgebung.addValue(varname + "_anf", tmppara)
      }
      else if(ausdruck.outputvars.isDefined(varname) && tmppara.isInstanceOf[ExpArray]) {
        var expa = new ExpArray(tmppara.asInstanceOf[ExpArray].range)
        ausdruck.funcconf.umgebung.setValue(varname, expa)

        // TODO alle *_anf variablen in den Zusicherungen ersetzen(trace)?
        if(ausdruck.funcconf.umgebung.getValue(varname + "_anf") == Some)
          ausdruck.funcconf.umgebung.setValue(varname + "_anf", expa)
        else
          ausdruck.funcconf.umgebung.addValue(varname + "_anf", expa)
      }
    }

    /**
     * Von der Eingabe abhängige Variablen setzen.
     */
    
    if(!ausdruck.inputvars.equals(null)) {
      var varsrelated = ausdruck.varsrelateoninput
      if(varsrelated != null) {
        for(i <- varsrelated) {
          var evalwert = i._2.evaluate(ausdruck.funcconf.umgebung) match {
            case Some(x:BigInt) => 
              if(x == BigInt(298171879)) {
                if(i._2.isInstanceOf[Name]) {
                  var tet:Expression =
                        ausdruck.funcconf.umgebung.getArray(i._2.asInstanceOf[Name]) match {
                    case x:ExpArray => x
                    case _ => null
                  }
                  if(tet == null)
                    Number(BigInt(0))
                  else
                    tet
                }
                else
                  Number(BigInt(0))
              }
              else
                Number(x) 
            case None => Number(BigInt(0))
          }
          if(evalwert != null)
            ausdruck.funcconf.umgebung.setValue(i._1.name, evalwert)
          else
            throw new Exception("Variableninitialisierung fehlerhaft!")
        }
      }
    }
    
    ausdruck.funcconf.numerate(1 :: number)
    var str = this.toString
    ausdruck.funcconf.trace(tt)
      
    /**
     * Out-Variablen der Umgebung des Unterprogramms zurückschreiben.
     */
    
    for(i <- 0 to ausdruck.params.length-1) {
      var varname = ausdruck.allvars.get(i) match {
        case Some(x) => x
        case None => null
      }

      if(varname != null && ausdruck.outputvars.isDefined(varname)) {
        env.setValue(ausdruck.params(i), ausdruck.funcconf.umgebung.getValue(varname).get)
      }
    }
    return (str, true, h+1) 
  }

  override def propagate(assI: Anweisung): Anweisungsfolge = {
    var tmp: ArrayBuffer[Anweisung] = ArrayBuffer()

    assI match {
      case Assertion (prefix: String, expr: BoolExpression) =>
        tmp.append(Assertion("", expr.reduce))
    }

    return Anweisungsfolge(tmp)
  }

  override def propagate(assV: Anweisung, assN: Anweisung): Anweisungsfolge = null

  def getAusdruck() : functionExpression = ausdruck
  
  def getVariables(a: ArrayBuffer[Name]) = {}
  
  def replaceVariable(fromVar: Name, toVar: Expression) : Unit = {
    ausdruck.replaceVariable(fromVar, toVar)
  }

}


 